#pragma once

#include <iostream>
#include <functional>

using std::cout;
using std::endl;
using std::function;

namespace Su
{

    // auto_ptr C98风格RAII,支持拷贝，但会有悬空问题
    template <class T>
    class auto_ptr
    {
    public:
        // 构造
        auto_ptr(T *ptr)
            : _ptr(ptr)
        {
        }

        // 拷贝构造
        auto_ptr(auto_ptr &ap)
            : _ptr(ap._ptr)
        {
            ap = nullptr;
        }

        auto_ptr &operator=(T *ptr)
        {
            _ptr = ptr;
            return *this;
        }

        T *Get() const // const修饰的是this指针的内容
        {
            return _ptr;
        }

        ~auto_ptr()
        {
            delete _ptr;
            cout << "delete ptr : " << _ptr << endl;
        }

    private:
        T *_ptr;
    };

    // 库里的模板参数: template <class T, class D = default_delete<T>> class unique_ptr;
    // unique_ptr C++11风格的RAII智能指针,不允许被拷贝
    // 定制删除器在模板给
    template <class T, class D>
    class unique_ptr
    {
    public:
        unique_ptr(T *ptr = nullptr)
            : _ptr(ptr)
        {
        }

        T& operator*()
        {
            return *_ptr;
        }
        T* operator->()
        {
            return _ptr;
        }

        ~unique_ptr()
        {
            // delete _ptr;
            D del;
            del(_ptr);
            cout << "delete ptr : " << _ptr << endl;
        }

        // 防拷贝
        unique_ptr(unique_ptr<T, D> &up) = delete;           // 拷贝函数
        unique_ptr operator=(unique_ptr<T, D> &up) = delete; // 赋值运算符重载
    private:
        T *_ptr;
    };

    template <class T>
    class share_ptr
    {
    public:
        // 构造函数
        share_ptr(T *ptr = nullptr)
            : _ptr(ptr),
              _pcount(new int(1))
        {}

        template<class D>
        share_ptr(T *ptr, D del)
            : _ptr(ptr),
              _pcount(new int(1)),
              _del(del)
        {}

        // 拷贝构造函数
        share_ptr(const share_ptr<T> &sp) // sp4(sp2) (sp4必须要未初始化)
            : _ptr(sp._ptr),
              _pcount(sp._pcount),
              _del(sp._del)
        {
            (*_pcount)++;
        }
        share_ptr &operator=(share_ptr &sp) // sp4 = sp2 (sp4有没有初始化都可以)
        {
            // 1.拷贝与被拷贝的对象都指向同一块内存空间
            if (sp._ptr == _ptr)
                return *this;

            // 2.不指向同一块内存空间(代码运行到这里,两个智能指针不相同)
            if (--(*_pcount) == 0)
            {
                // delete _ptr;
                _del(_ptr);
                delete _pcount;
            }

            _ptr = sp._ptr;
            _pcount = sp._pcount;
            _del = sp._del;
            (*_pcount)++;
            return *this;
        }
        T& operator*()
        {
            return *_ptr;
        }
        T* operator->()
        {
            return _ptr;
        }

        ~share_ptr()
        {
            if (--(*_pcount) == 0)
            {
                cout << "delete ptr : " << _ptr << endl;

                // delete _ptr;
                _del(_ptr);
                delete _pcount;
            }
        }

        int count()
        {
            return (*_pcount);
        }

        T* get() const
        {
            return _ptr;
        }
    private:
        T *_ptr;
        int *_pcount;
        function<void(T *ptr)> _del = [](T* ptr){delete ptr;};
    };

}